Class pgLaserEmitter extends Emitter
	Placeable;

const NumChildBeams=10;

var bool bStartupEnabled,bClientEnabled;
var() bool bBeamEnabled;
var() float MaxDistance;
var() int BeamHitDamage;
var() class<DamageType> BeamDamageType;
var() class<Emitter> ImpactEmitterFX;
var BeamEmitter Beam;
var Sound BeamingSound;
var transient float NextTraceTime;
var Emitter ImpactEmitter;
var pgLaserEmitterSeg LaserParts[NumChildBeams];
var int TagNum;

replication
{
	reliable if( Role == ROLE_Authority )
		bBeamEnabled;
}

simulated function PostBeginPlay()
{
	bStartupEnabled = bBeamEnabled;
	BeamingSound = AmbientSound;
	Beam = BeamEmitter(Emitters[0]);
}
simulated function PostNetBeginPlay()
{
	bClientEnabled = bBeamEnabled;
	if( Level.NetMode==NM_DedicatedServer )
	{
		Emitters[0].Disabled = true;
		Emitters[1].Disabled = true;
	}
	if( !bBeamEnabled )
		SetEnabled(false);
	bNetNotify = true;
}
simulated final function SetEnabled( bool bEnable )
{
	local byte i;

	bBeamEnabled = bEnable;
	if( bEnable )
	{
		AmbientSound = BeamingSound;
		Enable('Tick');
	}
	else
	{
		AmbientSound = None;
		Disable('Tick');
	}
	NetUpdateTime = Level.TimeSeconds-1;
	if( Level.NetMode==NM_DedicatedServer )
		return;
	if( bEnable )
	{
		Emitters[0].Reset();
		Emitters[1].Reset();
	}
	else
	{
		Emitters[0].Disabled = true;
		Emitters[1].Disabled = true;
		if( ImpactEmitter!=None )
		{
			ImpactEmitter.AmbientSound = None;
			ImpactEmitter.Kill();
			ImpactEmitter = None;
		}
		for( i=0; i<NumChildBeams; ++i )
			if( LaserParts[i]!=None )
				LaserParts[i].Destroy();
	}
}
function Trigger( Actor Other, Pawn EventInstigator )
{
	SetEnabled(!bBeamEnabled);
}
function Reset()
{
	SetEnabled(bStartupEnabled);
}
simulated function PostNetReceive()
{
	if( bClientEnabled!=bBeamEnabled )
	{
		bClientEnabled = bBeamEnabled;
		SetEnabled(bBeamEnabled);
	}
}

simulated final function SetLaserPart( vector A, vector B, byte i )
{
	local float D;

	if( i==0 )
	{
		D = VSize(A-B);
		Beam.BeamEndPoints[0].Offset.X.Min = D;
		Beam.BeamEndPoints[0].Offset.X.Max = D;
		return;
	}
	--i;
	if( LaserParts[i]==None )
	{
		LaserParts[i] = Spawn(Class'pgLaserEmitterSeg',,,A,rotator(B-A));
		LaserParts[i].AmbientSound = AmbientSound;
	}
	else
	{
		LaserParts[i].SetLocation(A);
		LaserParts[i].SetRotation(rotator(B-A));
	}
	D = VSize(A-B);
	LaserParts[i].Beam.BeamEndPoints[0].Offset.X.Min = D;
	LaserParts[i].Beam.BeamEndPoints[0].Offset.X.Max = D;
	LaserParts[i].UpdTag = TagNum;
}
simulated final function TraceBeam()
{
	local vector X,HL,HN,BeamStart;
	local Actor A;
	local byte i;

	++TagNum;
	BeamStart = Location;
	X = vector(Rotation);
	for( i=0; i<NumChildBeams; ++i )
	{
		foreach TraceActors(Class'Actor',A,HL,HN,BeamStart+X*MaxDistance,BeamStart)
		{
			if( A.Class==Class'pgPortalDecal' && pgPortalDecal(A).OtherSide!=None ) // Warp to other side.
			{
				if( Level.NetMode!=NM_DedicatedServer )
					SetLaserPart(BeamStart,HL,i);
				pgPortalDecal(A).WarpToCoordsPoint(HL);
				BeamStart = HL;
				pgPortalDecal(A).WarpToCoordsAxis(X);
				break;
			}
			else if( A==Level || TerrainInfo(A)!=None || A.bProjTarget || A.bBlockActors || A.Class==Class'LaserTarget' )
			{
				if( Level.NetMode!=NM_DedicatedServer )
					SetLaserPart(BeamStart,HL,i);
				A.TakeDamage(BeamHitDamage,None,HL,X*4000.f,BeamDamageType);
				i = 200;
				if( A.Class==Class'LaserTarget' )
					LaserTarget(A).HitByLaser();
				break;
			}
		}
	}
	if( Level.NetMode==NM_DedicatedServer )
		return;
	if( i>=200 )
	{
		if( ImpactEmitter==None )
		{
			ImpactEmitter = Spawn(ImpactEmitterFX,,,HL+HN*4.f,rotator(X));
			ImpactEmitter.AmbientSound = AmbientSound;
		}
		else
		{
			ImpactEmitter.SetLocation(HL+HN*4.f);
			ImpactEmitter.SetRotation(rotator(X));
		}
	}
	else if( ImpactEmitter!=None )
	{
		ImpactEmitter.AmbientSound = None;
		ImpactEmitter.Kill();
		ImpactEmitter = None;
	}
	for( i=0; i<NumChildBeams; ++i )
		if( LaserParts[i]!=None && LaserParts[i].UpdTag!=TagNum )
			LaserParts[i].Destroy();
}
simulated function Tick( float Delta )
{
	if( bBeamEnabled && NextTraceTime<Level.TimeSeconds )
	{
		NextTraceTime = Level.TimeSeconds+0.1f;
		TraceBeam();
	}
}

defaultproperties
{
	bEdShouldSnap=true
	bDirectional=true
	RemoteRole=ROLE_SimulatedProxy
	bAlwaysRelevant=true
	NetUpdateFrequency=0.5
	bBeamEnabled=true
	BeamHitDamage=10
	BeamDamageType=Class'DamTypeLaserBurn'
	bSkipActorPropertyReplication=true
	MaxDistance=2000
	ImpactEmitterFX=Class'pgLaserHitEmitter'
	SoundVolume=255
	bClientAnim=true

	Begin Object Class=BeamEmitter Name=BeamEmitter0
		BeamEndPoints(0)=(offset=(X=(Min=200.000000,Max=200.000000)))
		DetermineEndPointBy=PTEP_Offset
		BeamTextureVScale=0.500000
		FadeOut=True
		FadeIn=True
		ColorMultiplierRange=(Y=(Min=0.400000,Max=0.400000),Z=(Min=0.300000,Max=0.600000))
		FadeOutStartTime=0.080000
		FadeInEndTime=0.050000
		CoordinateSystem=PTCS_Relative
		MaxParticles=12
		StartSizeRange=(X=(Min=3.000000,Max=4.000000))
		Texture=Texture'KFX.TransTrailT'
		LifetimeRange=(Min=0.100000,Max=0.100000)
	End Object
	Emitters(0)=BeamEmitter'BeamEmitter0'

	Begin Object Class=SpriteEmitter Name=SpriteEmitter0
		FadeOut=True
		FadeIn=True
		UseSizeScale=True
		UseRegularSizeScale=False
		UniformSize=True
		ColorMultiplierRange=(Y=(Min=0.500000,Max=0.500000),Z=(Min=0.500000,Max=0.700000))
		FadeOutStartTime=0.070000
		FadeInEndTime=0.050000
		CoordinateSystem=PTCS_Relative
		MaxParticles=8
		SizeScale(0)=(RelativeTime=1.000000,RelativeSize=2.000000)
		StartSizeRange=(X=(Min=7.000000,Max=15.000000))
		Texture=Texture'KFX.MetalHitKF'
		LifetimeRange=(Min=0.100000,Max=0.150000)
	End Object
	Emitters(1)=SpriteEmitter'SpriteEmitter0'
}